/**
 * Copyright (c) 2005-2016, yinwer81 (yinwer81@aliyun.com)
 *
 * Licensed under the Apache License, Version 2.0
 */
package com.nozturn.throne.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.nozturn.throne.Constants;
import com.nozturn.throne.entity.OAuthInfoDTO;
import com.nozturn.throne.service.OAuthService;

@RestController
public class AccessTokenController {

    private Logger logger = LoggerFactory.getLogger(AccessTokenController.class);

    @Autowired
    private OAuthService oAuthService;

    /**
     * 打开accesstoken表单页面
     */
    @RequestMapping("/access")
    public ModelAndView access(Model model) {
        return new ModelAndView("accesstoken");
    }

    /**
     * 上面打开accesstoken表单页面，输入以下信息后POST到本方法，换取access_token令牌。
     * 
     * client_id 应用id<br>
     * client_secret 应用secret<br>
     * grant_type 用于传递授权码的参数名authorization_code<br>
     * code 用户登录授权后的授权码<br>
     * redirect_uri 回调地址<br>
     * 
     * @param request HttpServletRequest
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @RequestMapping("/accessToken")
    public HttpEntity token(HttpServletRequest request) throws OAuthSystemException {

        // 构建OAuth请求
        OAuthTokenRequest oauthRequest = null;
        try {
            oauthRequest = new OAuthTokenRequest(request);
        } catch (OAuthProblemException ope) {
            logger.error(ope.getMessage(), ope);
            // 构建错误响应
            OAuthResponse res = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST).error(ope).buildJSONMessage();
            return new ResponseEntity(res.getBody(), HttpStatus.valueOf(res.getResponseStatus()));
        }

        // 检查提交的客户端id是否正确
        if (!oAuthService.checkClientId(oauthRequest.getClientId())) {
            OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_CLIENT).setErrorDescription(Constants.INVALID_CLIENT_ID).buildJSONMessage();
            return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
        }

        // 检查客户端安全KEY是否正确
        if (!oAuthService.checkClientSecret(oauthRequest.getClientSecret())) {
            OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
                    .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT).setErrorDescription(Constants.INVALID_CLIENT_ID).buildJSONMessage();
            return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
        }

        String authorizationCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
        OAuthInfoDTO oauthInfoDTO = null;
        // 验证类型，有AUTHORIZATION_CODE/PASSWORD/REFRESH_TOKEN/CLIENT_CREDENTIALS
        if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE).equals(GrantType.AUTHORIZATION_CODE.toString())) {
            oauthInfoDTO = oAuthService.findAllByAuthorizationCode(authorizationCode);
            if (oauthInfoDTO == null) {
                OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                        .setError(OAuthError.TokenResponse.INVALID_GRANT).setErrorDescription(Constants.INVALID_AUTH_CODE).buildJSONMessage();
                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
            }
        }

        String accessToken = "";
        if (oauthInfoDTO.getAccessTokenPk() == null || oauthInfoDTO.getAccessToken() == null
                || !oauthInfoDTO.getAccessTokenValid().equals(new Integer(200))) {
            // 生成Access Token
            OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
            accessToken = oauthIssuerImpl.accessToken();
            oAuthService.addAccessToken(accessToken, oauthInfoDTO.getAuthorizationPk());
        } else {
            accessToken = oauthInfoDTO.getAccessToken();
        }

        // 生成OAuth响应
        OAuthResponse response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setAccessToken(accessToken)
                .setExpiresIn(String.valueOf(oAuthService.getExpireIn())).buildJSONMessage();

        // 根据OAuthResponse生成ResponseEntity
        return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

    }

    /**
     * 验证accessToken
     *
     * @param accessToken
     * @return
     */
    @SuppressWarnings("rawtypes")
    @RequestMapping(value = "/checkAccessToken", method = RequestMethod.POST)
    public ResponseEntity checkAccessToken(@RequestParam("accessToken") String accessToken) {
        boolean b = oAuthService.checkAccessToken(accessToken);
        return b ? new ResponseEntity(HttpStatus.valueOf(HttpServletResponse.SC_OK))
                : new ResponseEntity(HttpStatus.valueOf(HttpServletResponse.SC_UNAUTHORIZED));
    }

}
